/**
 * @file    drv_i2c_soft.c
 * @author  yhy
 * @brief   芯必达IM94x系列芯片, 软件模拟I2C抽象层
 * @version 1.00
 * @date    2025-07-16
 *
 * @copyright Copyright (c) 2025
 *
 * @details
 * Change Logs:
 * Date           Author       Notes
 * 2025-07-16     yhy          the first version V1.00
 *
 */
#include "drv_i2c_soft.h"

#include "common_debug.h"
#include "common_util.h"
#include "drv_gpio.h"

#define __I2C_DELAY__() common_util_delay_us(10) /* I2C延时 10us */

static result_e snf_drv_i2c_soft_gpio_config(const snf_i2c_soft_config_t *i2c_config);
static void     snf_drv_i2c_soft_set_scl(bool is_level_high);
static void     snf_drv_i2c_soft_set_sda(bool is_level_high);
static bool     snf_drv_i2c_soft_get_sda(void);
static void     snf_drv_i2c_soft_set_sda_input(void);
static void     snf_drv_i2c_soft_set_sda_output(void);

static snf_i2c_soft_config_t i2c_soft_config;      /* 软件模拟I2C配置 */
static uint8_t               i2c_soft_scl_idx = 0; /* SCL引脚索引 */

/**
 * @brief 初始化软件模拟I2C
 *
 * @param i2c_config    I2C配置
 * @return result_e     初始化结果, RESULT_STATUS_OK表示初始化成功, 其他值表示初始化失败
 */
result_e snf_drv_i2c_soft_init(const snf_i2c_soft_config_t *i2c_config)
{
    /* 参数校验 */
    if (!i2c_config || !i2c_config->scl_pin_num_list ||
        i2c_config->scl_count > I2C_SOFT_SCL_PIN_NUM_MAXSIZE) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    result_e result = RESULT_STATUS_OK;

    result = snf_drv_i2c_soft_gpio_config(i2c_config);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    i2c_soft_config = *i2c_config;

    /* 设置初始电平, SDA和SCL都为高, 总线呈空闲状态 */
    snf_drv_i2c_soft_set_scl(true);
    snf_drv_i2c_soft_set_sda(true);

    return RESULT_STATUS_OK;
}

/**
 * @brief 发送起始信号
 *
 */
void snf_drv_i2c_soft_start(void)
{
    snf_drv_i2c_soft_set_sda(true);
    snf_drv_i2c_soft_set_scl(true);
    __I2C_DELAY__();

    /* 拉低发送起始信号 */
    snf_drv_i2c_soft_set_sda(false);
    __I2C_DELAY__();

    /* 按照约定, 最后拉低SCL */
    snf_drv_i2c_soft_set_scl(false);
    __I2C_DELAY__();
}

/**
 * @brief 发送停止信号
 *
 */
void snf_drv_i2c_soft_stop(void)
{
    snf_drv_i2c_soft_set_sda(false);
    __I2C_DELAY__();

    snf_drv_i2c_soft_set_scl(true);
    __I2C_DELAY__();

    snf_drv_i2c_soft_set_sda(true);
    __I2C_DELAY__();
}

/**
 * @brief 发送ACK
 *
 */
void snf_drv_i2c_soft_ack(void)
{
    snf_drv_i2c_soft_set_sda(false);
    __I2C_DELAY__();

    snf_drv_i2c_soft_set_scl(true);
    __I2C_DELAY__();

    snf_drv_i2c_soft_set_scl(false);
    __I2C_DELAY__();

    snf_drv_i2c_soft_set_sda(true);
    __I2C_DELAY__();
}

/**
 * @brief 发送NACK
 *
 */
void snf_drv_i2c_soft_nack(void)
{
    snf_drv_i2c_soft_set_sda(true);
    __I2C_DELAY__();

    snf_drv_i2c_soft_set_scl(true);
    __I2C_DELAY__();

    snf_drv_i2c_soft_set_scl(false);
    __I2C_DELAY__();
}

/**
 * @brief 等待对方ACK响应
 *
 * @return snf_i2c_soft_resp_e I2C_SOFT_RESP_ACK or I2C_SOFT_RESP_NACK
 */
snf_i2c_soft_resp_e snf_drv_i2c_soft_wait4ack(void)
{
    snf_drv_i2c_soft_set_sda(true);
    __I2C_DELAY__();

    snf_drv_i2c_soft_set_scl(true);
    __I2C_DELAY__();

    snf_i2c_soft_resp_e ack_ans = !snf_drv_i2c_soft_get_sda() ? I2C_SOFT_RESP_ACK : I2C_SOFT_RESP_NACK;

    snf_drv_i2c_soft_set_scl(false);
    __I2C_DELAY__();

    return ack_ans;
}

/**
 * @brief 发送一个字节的数据
 *
 * @param tx_data 发送的一个字节数据
 */
void snf_drv_i2c_soft_send_byte(uint8_t tx_data)
{
    for (uint8_t i = 0; i < 8; ++i) {
        if (tx_data & 0x80) {
            snf_drv_i2c_soft_set_sda(true);
        }
        else {
            snf_drv_i2c_soft_set_sda(false);
        }
        __I2C_DELAY__();

        snf_drv_i2c_soft_set_scl(true);
        __I2C_DELAY__();

        snf_drv_i2c_soft_set_scl(false);
        __I2C_DELAY__();

        tx_data <<= 1;
    }
}

/**
 * @brief 接收一个字节的数据
 *
 * @return uint8_t 接收到的一个字节的数据
 */
uint8_t snf_drv_i2c_soft_recv_byte(void)
{
    uint8_t rx_data = 0;

    snf_drv_i2c_soft_set_sda(true); // 释放SDA总线
    __I2C_DELAY__();

    /* 将SDA设置为输入模式 */
    snf_drv_i2c_soft_set_sda_input();

    for (uint8_t i = 0; i < 8; ++i) {
        rx_data <<= 1;

        snf_drv_i2c_soft_set_scl(true);
        __I2C_DELAY__();

        uint8_t bit_value = snf_drv_i2c_soft_get_sda() ? 1 : 0;

        if (bit_value) {
            rx_data |= 0x01;
        }

        snf_drv_i2c_soft_set_scl(false);
        __I2C_DELAY__();
    }

    /* 恢复SDA为输出模式 */
    snf_drv_i2c_soft_set_sda_output();

    return rx_data;
}

/**
 * @brief 选择SCL引脚, 根据scl_pin_num_list的索引来确认scl_serial_num
 *
 * @param scl_serial_num      SCL引脚索引
 * @return result_e           选择结果, RESULT_STATUS_OK表示选择成功, 其他值表示选择失败
 */
result_e snf_drv_i2c_soft_select_sclx(uint8_t scl_serial_num)
{
    if (scl_serial_num >= i2c_soft_config.scl_count) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    snf_drv_i2c_soft_set_scl(true);

    i2c_soft_scl_idx = scl_serial_num;
    return RESULT_STATUS_OK;
}

/**
 * @brief 读取sda引脚是否位高电平
 *
 * @return true     sda引脚为高电平
 * @return false    sda引脚为低电平
 */
static bool snf_drv_i2c_soft_get_sda(void)
{
    snf_gpio_pin_level_e pin_level;
    snf_drv_gpio_read_pin(i2c_soft_config.sda_pin_num, &pin_level);

    return (pin_level == DRV_GPIO_PIN_LEVEL_HIGH);
}

/**
 * @brief 设置SCL电平
 *
 * @param is_level_high  是否设为高电平
 */
static void snf_drv_i2c_soft_set_scl(bool is_level_high)
{
    snf_gpio_pin_level_e pin_level = is_level_high ? DRV_GPIO_PIN_LEVEL_HIGH : DRV_GPIO_PIN_LEVEL_LOW;

    snf_drv_gpio_write_pin(i2c_soft_config.scl_pin_num_list[i2c_soft_scl_idx], pin_level);
}

/**
 * @brief 设置SDA电平
 *
 * @param is_level_high  是否设为高电平
 */
static void snf_drv_i2c_soft_set_sda(bool is_level_high)
{
    snf_gpio_pin_level_e pin_level = is_level_high ? DRV_GPIO_PIN_LEVEL_HIGH : DRV_GPIO_PIN_LEVEL_LOW;

    snf_drv_gpio_write_pin(i2c_soft_config.sda_pin_num, pin_level);
}

/**
 * @brief 初始化软件模拟I2C引脚
 *
 * @param i2c_config    I2C配置
 * @return result_e     初始化结果
 */
static result_e snf_drv_i2c_soft_gpio_config(const snf_i2c_soft_config_t *i2c_config)
{
    /* 此处不需要判定参数是否为NULL, 因为调用该函数前已经做了此操作 */
    snf_gpio_config_t gpio_config = { 0 };
    result_e          result      = RESULT_STATUS_OK;

    for (uint8_t i = 0; i < i2c_config->scl_count; ++i) {
        /* SCL pin config */
        gpio_config.pin_num    = i2c_config->scl_pin_num_list[i];
        gpio_config.mode       = DRV_GPIO_PIN_MODE_OUTPUT;
        gpio_config.init_level = DRV_GPIO_PIN_LEVEL_HIGH;
        result                 = snf_drv_gpio_init(&gpio_config);
        if (result != RESULT_STATUS_OK) {
            return result;
        }
    }

    /* SDA pin config */
    gpio_config.pin_num = i2c_config->sda_pin_num;
    result              = snf_drv_gpio_init(&gpio_config);

    return result;
}

/**
 * @brief 设置SDA为输入模式
 */
static void snf_drv_i2c_soft_set_sda_input(void)
{
    snf_drv_gpio_set_pin_mode(i2c_soft_config.sda_pin_num, DRV_GPIO_PIN_MODE_INPUT_FLOATING);
}

/**
 * @brief 设置SDA为输出模式
 */
static void snf_drv_i2c_soft_set_sda_output(void)
{
    snf_drv_gpio_set_pin_mode(i2c_soft_config.sda_pin_num, DRV_GPIO_PIN_MODE_OUTPUT);
}
